#!/usr/bin/python3
# -*- coding: utf-8 -*-
# ======================================#
# @Author   : duanqizhong
# @time     : 2022-8-6 23:01
# @file     : func
# @Software : PyCharm
# ======================================#
import base64
import hashlib
import os
import random
import re
import time
from datetime import datetime, timedelta

import ET
import paramiko
import xmltodict as xmltodict
import yaml
from paramiko import AuthenticationException
from pip._vendor import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder

from business.order.mock.settings import BASE_DIR
from settings import HEADERS


def get_yaml_dict(yaml_path):
    assert os.path.isfile(yaml_path), f"not fount yaml_path: {yaml_path}"
    fr = open(file=yaml_path, mode='r', encoding='utf-8')
    yaml_json = yaml.load(stream=fr, Loader=yaml.FullLoader)
    if "handlers" in yaml_json.keys():
        # log.yaml
        for key, value in yaml_json['handlers'].items():
            if "filename" in value:
                value['filename'] = os.path.join(BASE_DIR, value["filename"]).replace("\\", '/')
    return yaml_json


def session_form_post(op, url, data):
    """x-www-form-urlencoded: session POST请求"""
    try:
        msg = op.session.post(url, data=data).json()
        return msg
    except Exception as e:
        print(str(e))
        return {}


def session_form_get(op, url, data):
    """x-www-form-urlencoded: session GET请求"""
    try:
        msg = op.session.get(url, data=data).json()
        return msg
    except Exception as e:
        print(str(e))
        return {}


def session_post(op, url, data):
    """application/json: session POST请求"""
    try:
        msg = op.session.post(url, json=data, headers=HEADERS["json"]).json()
        return msg
    except Exception as e:
        print(str(e))
        return {}


def session_get(op, url, data=None):
    """application/json: session GET请求"""
    try:
        msg = op.session.get(url, json=data, headers=HEADERS["json"]).json()
        return msg
    except Exception as e:
        print(str(e))
        return {}


def session_muti_form(op, url, data):
    """multipart/form-data: requests POST请求"""
    try:
        mp_encoder = MultipartEncoder(
            fields=data
        )
        msg = op.session.post(url, data=mp_encoder, headers={"Content-Type": mp_encoder.content_type}).json()
    except Exception as e:
        print(str(e))
        return {}
    return msg


def form_post(url, data):
    """x-www-form-urlencoded: requests POST请求"""
    try:
        req = requests.post(url, data=data)
        try:
            msg = req.json()
            return msg
        except Exception as e:
            print(e)
            print(req.text)
    except Exception as e:
        print(str(e))
        return {}


def form_post_xml(url, data):
    """x-www-form-urlencoded: requests POST请求"""
    try:
        crud_response = requests.post(url, data=data)
        msg = xml_to_json(crud_response.content.decode(encoding="utf-8"))
    except Exception as e:
        print(str(e))
        return {}
    return msg


def form_get(url, data):
    """x-www-form-urlencoded: requests GET请求"""
    try:
        msg = requests.get(url, data=data).json()
    except Exception as e:
        print(str(e))
        return {}
    return msg


def post(url, data):
    """application/json: requests POST请求"""
    try:
        msg = requests.post(url, json=data, headers=HEADERS["json"]).json()
    except Exception as e:
        print(str(e))
        return {}
    return msg


def get(url, data=None):
    """application/json: requests GET请求"""
    try:
        msg = requests.get(url, json=data).json()
    except Exception as e:
        print(str(e))
        return {}
    return msg


def jenkins_args_parse(strs):
    """
    :param strs: 以 分号 逗号 空格 分隔的字符串
    :return: list
    """
    return [mystr for mystr in re.split(r'[;,\s]\s*', strs.strip()) if len(mystr) > 0]


def args_print(args):
    print("\n".join([f"{key}: {value}" for key, value in args.__dict__.items()]))


def random_name(length=3):
    # 百家姓
    baijiaxing = '赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞仁袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计伏成戴谈宋茅庞熊纪舒屈项祝董梁杜阮蓝闵席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田樊胡凌霍虞万支柯咎管卢莫经房裘缪干解鹰宗丁宣贲邓郁单杭洪包诸左石崔吉钮龚程嵇邢滑裴陆荣翁荀羊於惠甄曲家封芮羿储靳汲邴糜松井段富巫乌焦巴弓牧隗山谷车侯宓蓬全郗班仰秋仲伊宫宁仇栾暴甘钭厉戎祖武符刘景詹束龙叶幸司韶郜黎蓟博印宿白怀蒲台从鄂索咸籍赖卓蔺屠蒙池乔阴郁胥能苍双闻莘党翟谭贡劳逄姬申扶堵冉宰郦雍却璩桑桂濮牛寿通边扈燕冀郏浦尚农温别庄晏柴瞿阎充慕连茹习宦艾鱼容向古易慎戈廖庾终暨居衡步都耿满弘匡国文寇广禄阙东殴殳沃利蔚越夔隆师巩厍聂晁勾敖融冷訾辛阚那简饶空曾毋沙乜养鞠须丰巢关蒯相查后荆红游竺权逯盖後桓公万俟司马上官欧阳夏侯诸葛闻人东方赫连皇甫尉迟公羊澹台公冶宗政濮阳淳于单于太叔申屠公孙仲孙轩辕令狐钟离宇文长孙慕容鲜于闾丘司徒司空亓官司寇仉督子车颛孙端木巫马公西漆雕乐正壤驷公良拓拔夹谷宰父谷粱晋楚闫法汝鄢涂钦段干百里东郭南门呼延归海羊舌微生岳帅缑亢况后有琴梁丘左丘东门西门商牟佘佴伯赏南宫墨哈谯笪年爱阳佟第五言福百家姓终'
    name_list = random.choices(baijiaxing, k=length)
    return "".join(name_list)


def get_datetime(date_type="seconds", serial=False):
    """
    :param date_type:
    :param serial:
    :return:
    """
    if serial:
        if "day" == date_type:
            date_format = "%Y%m%d"
        elif "seconds" == date_type:
            date_format = "%Y%m%d%H%M%S"
        elif "microseconds" == date_type:
            date_format = "%Y%m%d%H%M%S.%f"
        else:
            date_format = "%Y%m%d%H%M%S"
    else:
        if "day" == date_type:
            date_format = "%Y-%m-%d"
        elif "seconds" == date_type:
            date_format = "%Y-%m-%d %H:%M:%S"
        else:
            date_format = "%Y-%m-%d %H:%M:%S"

    return datetime.now().strftime(date_format)


def get_releated_time(time_type="hours", interval=1):
    date_format = "%Y-%m-%d %H:%M:%S"
    if time_type == "hours":
        mytime = (datetime.now() + timedelta(hours=interval)).strftime(date_format)
    elif time_type == "days":
        mytime = (datetime.now() + timedelta(days=interval)).strftime(date_format)
    else:
        mytime = (datetime.now() + timedelta(minutes=interval)).strftime(date_format)
    return mytime


def check_datetime_str(datestr):
    try:
        time.strptime(datestr, "%Y-%m-%d %H:%M:%S")
        return True
    except Exception as e:
        return False

def get_dir_file(dir_path, filter: str = None, dir_bool=True, file_bool=True):
    files = []
    if not os.path.isdir(dir_path):
        return files

    for file in os.listdir(dir_path):
        if filter:
            if not file.startswith(filter):
                continue

        if dir_bool:
            if os.path.isdir(os.path.join(dir_path, file)):
                files.append(file)
                continue

        if file_bool:
            if os.path.isfile(os.path.join(dir_path, file)):
                files.append(file)
                continue

    return files


def xml_to_json(xml_str):
    """xml 转换成 json"""
    json_parse = xmltodict.parse(xml_input=xml_str)
    return json_parse


def json_to_xml(json_str, pretty=0, full_document=True):
    """json 转换成 xml"""
    xml_parse = xmltodict.unparse(json_str, pretty=pretty, full_document=full_document)
    return xml_parse


def json_to_etree_ET(json_data):
    xml_str = json_to_xml(json_data)
    etree = ET.fromstring(xml_str)
    return etree


def xls_read(xls_path, sheet_index=0, sheet_name=None):
    xls = xlrd.open_workbook(xls_path)
    import_flag = xls.sheet_loaded(sheet_name or sheet_index)
    if import_flag:
        data = []
        if sheet_name:
            table = xls.sheet_by_name(sheet_name)
        else:
            table = xls.sheet_by_index(sheet_index)
        nrows = table.nrows
        for row in range(nrows):
            data.append(table.row_values(row))
        return data
    return []


def xls_write(xls_path, data, sheet_name="Sheet1"):
    assert xls_path.split('.')[-1].lower() == 'xls', "filename format: filename.xls"
    workbook = xlwt.Workbook(encoding='utf-8')
    worksheet = workbook.add_sheet(sheet_name)
    nrows = len(data)
    for row in range(nrows):
        ncols = len(data[row])
        for col in range(ncols):
            worksheet.write(row, col, data[row][col])
    workbook.save(xls_path)

    return True


def query_sql(op, database, sql, all=True):
    """查询数据库"""
    op.connect(database)
    if all:
        result = op.fetchall(sql)
    else:
        result = op.fetchone(sql)
    op.close()
    return result


def exec_sql(op, database, sql):
    """操作数据库"""
    op.connect(database)
    flag = op.exec(sql)
    if flag:
        op.commit()
    op.close()
    return flag


def ssh_client(host, cmd, pri_key, user='root', port=22, timeout=10):
    """"""
    infos = {
        "status": True,
        "msg": "ok"
    }
    if not os.path.exists(pri_key):
        raise Exception(f"not found path: {pri_key}")

    key = paramiko.RSAKey.from_private_key_file(pri_key)
    ssh = paramiko.SSHClient()
    # ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        ssh.connect(hostname=host, port=port, username=user, pkey=key)
        stdin, stdout, stderr = ssh.exec_command(cmd)
        # infos["stdin"] = stdin.read().decode("utf-8")
        infos["stdout"] = stdout.read().decode("utf-8")
        infos["stderr"] = stderr.read().decode("utf-8")
    except AuthenticationException as auth_failed:
        infos["status"] = False
        infos["msg"] = str(auth_failed)
    except Exception as e:
        infos["status"] = False
        infos["msg"] = str(e)
    finally:
        if ssh:
            ssh.close()
    return infos


def md5_sum(strs, encoding="utf-8"):
    """
    request_time + express_id + key
   示例input：15115080747181001123456 => bbc11710398ec8a467e1cc8d57d8f33e
   """
    # 创建hash对象
    md5 = hashlib.md5()
    # 使用字符串更新hash对象
    md5.update(strs.encode(encoding=encoding))
    # 返回16进制数字字符串
    md5_digest = md5.hexdigest()
    return md5_digest


def crypt_md5_base64(strs="<order></order>123456", encoding='utf-8'):
    """
    示例input: <order></order>123456 => LghTkEmsD2tbQ3fsIBRcBg==
    """
    # 创建hash对象
    md5 = hashlib.md5()
    # 使用字符串更新hash对象
    md5.update(strs.encode(encoding=encoding))
    # 返回二进制摘要
    md5_digest = md5.digest()
    # md5.hexdigest() #返回16进制数字字符串
    # 输入需要是二进制，进行base64编码；然后将加密结果编码成字符串
    base_encode_str = base64.b64encode(md5_digest).decode("utf-8")
    # print(base_encode_str)
    return base_encode_str


def crypt_base64_contain_md5(strs, encoding="utf-8"):
    md5_str = md5_sum(strs, encoding)
    base_encode_byte = base64.b64encode(bytes(md5_str, encoding=encoding))
    base_encode_str = str(base_encode_byte, encoding=encoding)
    return base_encode_str


def compare_json_keys(input_dict, reference_dict):
    """输入的dict或参照的dict非dict,返回False"""
    # 类型不相等，一定不一样直接返回
    if type(input_dict) != type(reference_dict):
        print("type is different!")
        return False

    def compatible_list(input_list, reference_list):
        for i_list in input_list:
            if isinstance(i_list, dict):
                if isinstance(reference_list[0], dict):
                    print("compatible_info", i_list, reference_list[0])
                    if not compare_json_keys(i_list, reference_list[0]):
                        return False
                else:
                    print("type False")
                    print(type(i_list), i_list)
                    print(type(reference_list[0]), reference_list[0])
                    return False
            elif isinstance(i_list, list):
                if isinstance(reference_list[0], list):
                    print("compatible_info", i_list, reference_list[0])
                    if not compatible_list(i_list, reference_list[0]):
                        return False
                else:
                    print("type False")
                    print(type(i_list), i_list)
                    print(type(reference_list), reference_list)
                    return False
            else:
                # 列表内具体内容无法对比，不一定每次都按顺序返回；判断元数个数也不一定对;假设都是数组元素，则认为无差异
                continue
        else:
            return True

    if isinstance(input_dict, list):
        print(input_dict, reference_dict)
        return compatible_list(input_dict, reference_dict)
    # 既不是list 又不是dict，不能进行比较；不进行值比较
    if not isinstance(input_dict, dict): return False
    input_dict_keys_set = set(input_dict.keys())
    reference_dict_keys_set = set(reference_dict.keys())
    if input_dict_keys_set == reference_dict_keys_set:
        for key in input_dict_keys_set:
            if isinstance(input_dict[key], dict):
                if isinstance(reference_dict[key], dict):
                    print("compare_dict_keys_info", input_dict[key], reference_dict[key])
                    if not compare_json_keys(input_dict[key], reference_dict[key]):
                        return False
                else:
                    print("type False")
                    print(type(input_dict[key]), input_dict[key])
                    print(type(reference_dict[key]), reference_dict[key])
                    return False
            elif isinstance(input_dict[key], list):
                if isinstance(reference_dict[key], list):
                    if not compatible_list(input_dict[key], reference_dict[key]):
                        return False
                else:
                    print("type False")
                    print(type(input_dict[key]), input_dict[key])
                    print(type(reference_dict[key]), reference_dict[key])
                    return False
            elif type(input_dict[key]) != type(reference_dict[key]):
                print("type False")
                print(type(input_dict[key]), input_dict[key])
                print(type(reference_dict[key]), reference_dict[key])
                return False
        else:
            return True
    else:
        print("keys False")
        print(input_dict_keys_set, input_dict_keys_set - reference_dict_keys_set)
        print(reference_dict_keys_set, reference_dict_keys_set - input_dict_keys_set)
        return False


def compare_json(input_dict, reference_dict):
    """输入的dict或参照的dict非dict,返回False"""
    # 类型不相等，一定不一样直接返回
    if type(input_dict) != type(reference_dict):
        print("type is different!")
        return False

    def compatible_list(input_list, reference_list):
        for i_list in input_list:
            if isinstance(i_list, dict):
                if isinstance(reference_list[0], dict):
                    print("compatible_info", i_list, reference_list[0])
                    if not compare_json(i_list, reference_list[0]):
                        return False
                else:
                    print("type False")
                    print(type(i_list), i_list)
                    print(type(reference_list[0]), reference_list[0])
                    return False
            elif isinstance(i_list, list):
                if isinstance(reference_list[0], list):
                    print("compatible_info", i_list, reference_list[0])
                    if not compatible_list(i_list, reference_list[0]):
                        return False
                else:
                    print("type False")
                    print(type(i_list), i_list)
                    print(type(reference_list), reference_list)
                    return False
            else:
                # 列表内具体内容无法对比，不一定每次都按顺序返回；判断元数个数也不一定对;假设都是数组元素，则认为无差异
                continue
        else:
            return True

    if isinstance(input_dict, list):
        print(input_dict, reference_dict)
        return compatible_list(input_dict, reference_dict)
    # 既不是list 又不是dict，不能进行比较；不进行值比较
    if not isinstance(input_dict, dict): return False
    input_dict_keys_set = set(input_dict.keys())
    reference_dict_keys_set = set(reference_dict.keys())
    # 参照的key存在，输入不存在
    if len(reference_dict_keys_set - input_dict_keys_set): return False
    # 必须key校验
    for key in reference_dict_keys_set:
        if isinstance(input_dict[key], dict):
            if isinstance(reference_dict[key], dict):
                print("compare_dict_keys_info", input_dict[key], reference_dict[key])
                if not compare_json(input_dict[key], reference_dict[key]):
                    return False
            else:
                print("type False")
                print(type(input_dict[key]), input_dict[key])
                print(type(reference_dict[key]), reference_dict[key])
                return False
        elif isinstance(input_dict[key], list):
            if isinstance(reference_dict[key], list):
                if not compatible_list(input_dict[key], reference_dict[key]):
                    return False
            else:
                print("type False")
                print(type(input_dict[key]), input_dict[key])
                print(type(reference_dict[key]), reference_dict[key])
                return False
        elif type(input_dict[key]) != type(reference_dict[key]):
            print("type False")
            print(type(input_dict[key]), input_dict[key])
            print(type(reference_dict[key]), reference_dict[key])
            return False
    else:
        return True


def quick_sort(sort_list):
    assert isinstance(sort_list, list or tuple), f"输入的数据费列表"

    def start_sort(tasks, start, end):
        if start > end:
            return
        i, j = start, end
        flag = tasks[start]
        # print(flag)
        while True:
            # 右->左
            while j > i and tasks[j] >= flag:
                j -= 1
            # 左->右
            while i < j and tasks[i] <= flag:
                i += 1
            if i < j:
                tasks[i], tasks[j] = tasks[j], tasks[i]
            elif i == j:
                tasks[start], tasks[i] = tasks[i], tasks[start]
                break
        start_sort(tasks, start, i - 1)
        start_sort(tasks, i + 1, end)

    start = 0
    end = len(sort_list) - 1
    start_sort(sort_list, start, end)
    return sort_list
